/**
 *  This file is part of OhSnap.
 *
 * 	Copyright (c) 2009 Gabriel Mendonça and Marcelo Machado
 * 
 *  OhSnap is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  OhSnap is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with OhSnap.  If not, see <http://www.gnu.org/licenses/>.
 *  
 */
package br.mm.cg;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PVector;
import br.mm.cg.particles.GeneratorManager;
import br.mm.midi.MidiNote;
import br.mm.midi.MidiPlayer;

/**
 * @author mendonça
 * 
 */
public class Animation extends PApplet {

	public static String midiFilePath = "data/canon.mid";
	public static int frameRate = 30;
	public static boolean stereo3d = false;
	public static float[] initialColor = new float[] {100, 150, 200};
	
	public static final int WINDOW_WIDTH = 640;
	public static final int WINDOW_HEIGHT = 480;

	private static final long serialVersionUID = -1490182685709005591L;
	
	private List<MidiNote> notes;
	private GeneratorManager generatorManager;
	private Camera camera;
	private PGraphics pGraphics;
	private PGraphics leftPGraphics;
	private PGraphics rightPGraphics;
	private float[] backgroundColor;
	private PVector maxClip;
	private PVector minClip;

	/*
	 * (non-Javadoc)
	 * 
	 * @see processing.core.PApplet#setup()
	 */
	/**
	 * Called when the application is starting, sets up the scene.<br>
	 * Starts the MIDI player and instantiates the GeneratorManager.
	 */
	@Override
	public void setup() {
		initRenderers();

		generatorManager = new GeneratorManager(this, maxClip, minClip, initialColor);
		camera = new Camera(this, stereo3d);
		
		startMusic();

		frameRate(frameRate);
		initBackgroundColor();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see processing.core.PApplet#draw()
	 */
	/**
	 * Called on each frame, draws the scene. All Generators will be updated
	 * according to the played notes.
	 */
	@Override
	public void draw() {
		if (stereo3d) {
			drawScene(leftPGraphics);
			image(leftPGraphics, 0, 0);
			
			drawScene(rightPGraphics);
			image(rightPGraphics, WINDOW_WIDTH, 0);
			
		} else {
			drawScene(pGraphics);
			image(pGraphics, 0, 0);
		}
		
		notes.clear();	
	}

	
	/**
	 * Draws the scene using the provided PGraphics object.
	 * @param pg the PGraphics where the scene will be drawn.
	 */
	private void drawScene(PGraphics pg) {
		pg.beginDraw();
		
		pg.background(backgroundColor[0], backgroundColor[1], backgroundColor[2]);
		camera.setUp(pg);
		pg.lights();
		generatorManager.drawAll(notes, pg);
		
		pg.endDraw();	
	}

	/**
	 * Creates the note buffer and starts to play the choosed MIDI file.
	 */
	private void startMusic() {
		try {
			notes = Collections.synchronizedList(new LinkedList<MidiNote>());
			MidiPlayer midiPlayer = new MidiPlayer(midiFilePath,
					generatorManager);
			midiPlayer.play(notes);
	
		} catch (Exception e) {
			exit();
		}
	}

	private void initRenderers() {
		if (stereo3d) {
			size(WINDOW_WIDTH * 2, WINDOW_HEIGHT);
			
			leftPGraphics = createGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, P3D);
			rightPGraphics = createGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, P3D);
			
			initPGraphics(leftPGraphics);
			initPGraphics(rightPGraphics);
	
			maxClip = new PVector(width * 0.75f, height, -150);
			minClip = new PVector(width * 0.25f, 0f, -450);
		}
		else {
			size(WINDOW_WIDTH, WINDOW_HEIGHT);
			
			pGraphics = createGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, P3D);
			initPGraphics(pGraphics);
	
			maxClip = new PVector(width, height, -150);
			minClip = new PVector(0f, 0f, -450);
		}
	}

	/**
	 * @param pg
	 */
	private void initPGraphics(PGraphics pg) {
		pg.beginDraw();
		pg.noStroke();
		pg.endDraw();
	}

	/**
	 * Chooses the initial background color.
	 */
	private void initBackgroundColor() {
		backgroundColor = initialColor.clone();
		for (int i = 0; i < 3; i++) {
			backgroundColor[i] = 255.0f - backgroundColor[i];
		}
	}
}
